/**
 * 
 */
package it.polimi.cg16.net;

import it.polimi.cg16.controller.Game;
import it.polimi.cg16.controller.PlayerController;
import it.polimi.cg16.exceptions.InactivePlayerException;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.Timer;

/**
 * @author Andrea
 * 
 */
public class RmiAdapter extends UnicastRemoteObject implements Adapter {
    private static final Logger LOGGER = Logger.getGlobal();
    private static final String CONTEXT = "context";
    private static final String ME = "server";
    private static final String CLIENT = "client";
    private static final int RESPONSE_TIME_OUT = 120000;
    private PlayerController playerController;
    RmiComm communication;
    protected boolean activePlayer = true;

    public RmiAdapter(int number) throws RemoteException {
        RmiCommImpl rmiCommunication = new RmiCommImpl();
        communication = (RmiComm) UnicastRemoteObject.exportObject(rmiCommunication, 1099 + number);
        Registry registry = LocateRegistry.getRegistry();
        registry.rebind("RmiCommunication" + number, communication);
        System.out.println("Rmi Server is ready to listen...");
    }

    /**
     * Send a bye message
     * 
     * @throws IOException
     */
    public void byeMessage() {
        sendMessage("bye");
    }

    /**
     * Set the player controller to the adapter
     * 
     * @param playerController
     */
    public void setPlayerController(PlayerController playerController) {
        this.playerController = playerController;
    }

    /**
     * Method to show result to client
     */
    @Override
    public void showResults(Game game) {
        sendMessage("#showResults#");
        sendInt(playerController.getPlayer().getPoints());
    }

    /**
     * Receive string from client
     * 
     * @return
     * @throws InactivePlayerException
     */
    @Override
    public String readString() throws InactivePlayerException {
        try {
            Timer timer = new Timer(RESPONSE_TIME_OUT, new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent arg0) {
                    activePlayer = false;
                }

            });
            timer.start();
            while (true) {
                if (communication.getRead() == 0 && CLIENT.equals(communication.getSender()) && activePlayer) {
                    timer.stop();
                    break;
                }
                if (!activePlayer) {
                    throw new InactivePlayerException();
                }
            }

            return communication.readMessage(ME);
        } catch (RemoteException e) {
            LOGGER.log(Level.FINE, CONTEXT, e);
        }
        return null;
    }

    /**
     * Receive integer from client
     * 
     * @return
     * @throws InactivePlayerException
     */
    @Override
    public int readInt() throws InactivePlayerException {
        try {
            Timer timer = new Timer(RESPONSE_TIME_OUT, new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent arg0) {
                    activePlayer = false;
                }

            });
            timer.start();
            while (true) {
                if (communication.getRead() == 0 && CLIENT.equals(communication.getSender()) && activePlayer) {
                    timer.stop();
                    break;
                }
                if (!activePlayer) {
                    throw new InactivePlayerException();
                }
            }
            return communication.readNumber(ME);
        } catch (RemoteException e) {
            LOGGER.log(Level.FINE, CONTEXT, e);
        }
        return -1;
    }

    /**
     * Send message to the client
     */
    @Override
    public void sendMessage(String msg) {
        try {
            while (true) {
                if (communication.getRead() == 1) {
                    break;
                }
            }
            communication.writeMessage(msg, ME);
        } catch (RemoteException e) {
            LOGGER.log(Level.FINE, CONTEXT, e);
        }
    }

    /**
     * Send integer to the client
     * 
     * @param num
     */
    @Override
    public void sendInt(int num) {
        try {
            while (true) {
                if (communication.getRead() == 1) {
                    break;
                }
            }
            communication.writeNumber(num, ME);
        } catch (RemoteException e) {
            LOGGER.log(Level.FINE, CONTEXT, e);
        }

    }

}